package _6_state

import "fmt"

type State int

const (
	State1 State = iota + 1
	State2
	State3
)

type Context struct {
	state State
}

func (c *Context) DoSomething1() {
	if c.state == State1 {
		fmt.Println("Do Something 1 and change State1 to State2")
		c.state = State2
	} else {
		fmt.Println("Don't do anything  state is not State 1")
	}
}

func (c *Context) DoSomething2() {
	if c.state == State2 {
		fmt.Println("Do Something 2 and change State2 to State3")
		c.state = State3
	} else {
		fmt.Println("Don't do anything state is not State 2")
	}
}

// -- 查表法 将状态的转移和发生的动作做成一个表配置动作

//StateTransition 有限状态机
type StateTransition interface {
	DoSomething1()
	DoSomething2()
	DoSomething3()
}

type AbstractState struct {
	Context *StateMachineContext
}

func (a *AbstractState) DoSomething1() {
	panic("implement me")
}

func (a *AbstractState) DoSomething2() {
	panic("implement me")
}

func (a *AbstractState) DoSomething3() {
	panic("implement me")
}

type State1Transition struct {
	AbstractState
}

func (a *State1Transition) DoSomething1() {
	fmt.Println("state 1 do something 1 and change state 1 to 2")
	a.Context.CurrentState = State2
}

func (a *State1Transition) DoSomething2() {
	fmt.Println("state 1 do not anything")
}

func (a *State1Transition) DoSomething3() {
	fmt.Println("state 1 do not anything")
}

type State2Transition struct {
	AbstractState
}

func (a *State2Transition) DoSomething1() {
	fmt.Println("state 2 do not anything")
}

func (a *State2Transition) DoSomething2() {
	fmt.Println("state 2 do something 2 and change state 2 to 3")
	a.Context.CurrentState = State3
}

func (a *State2Transition) DoSomething3() {
	fmt.Println("state 2 do not anything")
}

type State3Transition struct {
	AbstractState
}

func (a *State3Transition) DoSomething1() {
	fmt.Println("state 3 do not anything")
}

func (a *State3Transition) DoSomething2() {
	fmt.Println("state 3 do not anything")
}

func (a *State3Transition) DoSomething3() {
	fmt.Println("state 3 do something 3 and change state 3 to 1")
	a.Context.CurrentState = State1
}

type StateMachineContext struct {
	StateTransitions map[State]StateTransition
	CurrentState     State
}

func NewStateMachineContext() *StateMachineContext {
	context := &StateMachineContext{
		CurrentState: State1,
	}
	abstractState := AbstractState{
		Context: context,
	}

	stateTransitions := map[State]StateTransition{
		State1: &State1Transition{
			AbstractState: abstractState,
		},
		State2: &State2Transition{
			AbstractState: abstractState,
		},
		State3: &State3Transition{
			AbstractState: abstractState,
		},
	}

	context.StateTransitions = stateTransitions
	return context
}

func (s *StateMachineContext) DoSomething1() {
	s.StateTransitions[s.CurrentState].DoSomething1()
}

func (s *StateMachineContext) DoSomething2() {
	s.StateTransitions[s.CurrentState].DoSomething2()
}

func (s *StateMachineContext) DoSomething3() {
	s.StateTransitions[s.CurrentState].DoSomething3()
}
